package wxpay

import (
	"bgs/db"
	sqlc "bgs/db/sqlc"
	"bgs/grpc/imp/enums"
	nsqpUtil "bgs/nsqp/util"
	brandService "bgs/service/brand"
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"github.com/nsqio/go-nsq"
	"go.uber.org/zap"
	"strconv"
	// "strings"
)

// ApplymentNotification 进件状态更新通知
type ApplymentNotification struct {
	ApplyNo            string `json:"apply_no"`
	BizApplyNo         string `json:"biz_apply_no"`
	BrandID            string `json:"brand_id"` //商户ID (本地brand_id的映射sg_id)
	MchID              string `json:"mch_id"`
	SubMchID           string `json:"sub_mch_id"`
	ApplymentType      string `json:"applyment_type"`
	ApplymentState     string `json:"applyment_state"`
	ApplymentStateDesc string `json:"applyment_state_desc"`
	Timestamp          int64  `json:"timestamp"`
}

// ApplymentHandler WxpayApplyment message handler
type ApplymentHandler struct {
	dao          *db.PgDao
	slog         *zap.SugaredLogger
	topic        string
	failover     *nsqpUtil.NsqFailover
	brandService *brandService.BrandServiceImp
}

// NewApplymentHandler create a new handler for WxpayApplyment
func NewApplymentHandler(
	pgdao *db.PgDao,
	slog *zap.SugaredLogger,
	topic string,
	failover *nsqpUtil.NsqFailover,
	brandService *brandService.BrandServiceImp,
) *ApplymentHandler {
	return &ApplymentHandler{
		dao:          pgdao,
		slog:         slog.With("module", "ApplymentHandler"),
		topic:        topic,
		failover:     failover,
		brandService: brandService,
	}
}

// HandleMessage implements the Handler interface.
func (h *ApplymentHandler) HandleMessage(m *nsq.Message) error {
	if len(m.Body) == 0 {
		// Returning nil will automatically send a FIN command to NSQ to mark the message as processed.
		return nil
	}

	h.slog.Infof("message=>%s", string(m.Body))

	v := &ApplymentNotification{}
	if decodeErr := json.NewDecoder(bytes.NewReader(m.Body)).Decode(v); decodeErr != nil {
		return fmt.Errorf("无法解析信息[ApplymentNotification]: %s", decodeErr.Error())
	}

	ctx := context.Background()
	var err error
	defer h.failover.BackupSubMsgWhenHandleFail(ctx, &err, nsqpUtil.BackupSubMsgParam{
		Ts:    v.Timestamp,
		Topic: h.topic,
		Mbody: m.Body,
	})

	sgID, err := strconv.ParseInt(v.BrandID, 10, 64)
	if err != nil {
		return fmt.Errorf("无效的brandID:%s", err.Error())
	}

	// 上游系统的brandID是本系统的sgID
	brand, err := h.dao.Q.GetBrandByRemotePK(ctx, sgID)
	if err != nil {
		return err
	}
	// 获取wxpay_applyment
	wxpayApplyment, err := h.dao.Q.GetWxpayApplymentByBrandID(ctx, brand.ID)
	if err != nil {
		return err
	}

	// 判断状态变化,调用apply_query
	if wxpayApplyment.ApplyState.String != v.ApplymentState {
		h.slog.Infof("wxpayApplyment状态发生变化 %s => %s", wxpayApplyment.ApplyState, v.ApplymentState)

		err = h.dao.NewTxRunner().SqlcExecTx(ctx, func(q *sqlc.Queries) (err error) {

			synced, err := h.brandService.SyncWxpayApplyment(ctx, q, brandService.SyncWxpayApplymentParam{
				WxpayApplymentPtr: &wxpayApplyment,
			})
			if err != nil {
				return
			}
			h.slog.Infof("更新微信支付商户进件代理信息-from nsq ok")
			applyState := synced.ApplyState.String
			subMchID := synced.WxpayMchIDAsSub.String
			if applyState == string(enums.ApplymentStateFinish) {

				// 内部有清空缓存,尽量把该方法放到事务最后
				err = h.brandService.FinishWxpayApplyment(ctx, q, brandService.FinishWxpayApplymentParam{
					WxpayApplymentPtr: &wxpayApplyment,
					SubMchID:          subMchID,
				})
				if err != nil {
					return
				}
				h.slog.Infof("商户进件完成,更新品牌扩展信息-from nsq ok")
			}
			return
		})
		if err != nil {
			return err
		}
	}

	// Returning a non-nil error will automatically send a REQ command to NSQ to re-queue the message.
	return nil
}
